#include "WorkbenchPy.h"
#include "PyObjectBase.h"

PyTypeObject WorkbenchPy::Type = {
	PyVarObject_HEAD_INIT(&PyType_Type,0)
	"Gui.Workbench",     /*tp_name*/
	sizeof(WorkbenchPy),                       /*tp_basicsize*/
	0,                                                /*tp_itemsize*/
	/* methods */
	PyDestructor,                                     /*tp_dealloc*/
#if PY_VERSION_HEX >= 0x03080000
	0,                                                /*tp_vectorcall_offset*/
#else
	nullptr,                                          /*tp_print*/
#endif
	nullptr,                                          /*tp_getattr*/
	nullptr,                                          /*tp_setattr*/
	nullptr,                                          /*tp_compare*/
	__repr,                                           /*tp_repr*/
	nullptr,                                          /*tp_as_number*/
	nullptr,                                          /*tp_as_sequence*/
	nullptr,                                          /*tp_as_mapping*/
	nullptr,                                          /*tp_hash*/
	nullptr,                                          /*tp_call */
	nullptr,                                          /*tp_str  */
	__getattro,                                       /*tp_getattro*/
	__setattro,                                       /*tp_setattro*/
	/* --- Functions to access object as input/output buffer ---------*/
	nullptr,                                          /* tp_as_buffer */
	/* --- Flags to define presence of optional/expanded features */
	Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DEFAULT,        /*tp_flags */
	"This is the base class for workbenches",           /*tp_doc */
	nullptr,                                          /*tp_traverse */
	nullptr,                                          /*tp_clear */
	nullptr,                                          /*tp_richcompare */
	0,                                                /*tp_weaklistoffset */
	nullptr,                                          /*tp_iter */
	nullptr,                                          /*tp_iternext */
	WorkbenchPy::Methods,                     /*tp_methods */
	nullptr,                                          /*tp_members */
	WorkbenchPy::GetterSetter,                     /*tp_getset */
	&PyObjectBase::Type,                        /*tp_base */
	nullptr,                                          /*tp_dict */
	nullptr,                                          /*tp_descr_get */
	nullptr,                                          /*tp_descr_set */
	0,                                                /*tp_dictoffset */
	__PyInit,                                         /*tp_init */
	nullptr,                                          /*tp_alloc */
	WorkbenchPy::PyMake,/*tp_new */
	nullptr,                                          /*tp_free   Low-level free-memory routine */
	nullptr,                                          /*tp_is_gc  For PyObject_IS_GC */
	nullptr,                                          /*tp_bases */
	nullptr,                                          /*tp_mro    method resolution order */
	nullptr,                                          /*tp_cache */
	nullptr,                                          /*tp_subclasses */
	nullptr,                                          /*tp_weaklist */
	nullptr,                                          /*tp_del */
	0,                                                /*tp_version_tag */
	nullptr                                           /*tp_finalize */
#if PY_VERSION_HEX >= 0x03090000
	,nullptr                                          /*tp_vectorcall */
#elif PY_VERSION_HEX >= 0x03080000
	,nullptr                                          /*tp_vectorcall */
	/* bpo-37250: kept for backwards compatibility in CPython 3.8 only */
	,nullptr                                          /*tp_print */
#endif
};

PyMethodDef WorkbenchPy::Methods[] = {
	{"Initialize",
		reinterpret_cast<PyCFunction>(staticCallback_Initialize),
		METH_VARARGS,
		"Initialize"
	},
	{"GetClassName",
		reinterpret_cast<PyCFunction>(staticCallback_GetClassName),
		METH_VARARGS,
		"Return the class name"
	},
	{nullptr, nullptr, 0, nullptr}		/* Sentinel */
};

PyGetSetDef WorkbenchPy::GetterSetter[] = {
	{"MenuText",
		(getter)staticCallback_getMenuText,
		(setter)staticCallback_setMenuText,
		"The menu text",
		nullptr
	},
	{"ToolTip",
		(getter)staticCallback_getToolTip,
		(setter)staticCallback_setToolTip,
		"The menu text",
		nullptr
	},
	{"Icon",
		(getter)staticCallback_getIcon,
		(setter)staticCallback_setIcon,
		"The menu text",
		nullptr
	},
	{nullptr, nullptr, nullptr, nullptr, nullptr}		/* Sentinel */
};


PyObject* WorkbenchPy::staticCallback_getMenuText(PyObject* self, PyObject* args)
{
	// make sure that not a null pointer is passed
	if (!self) {
		PyErr_SetString(PyExc_TypeError, "descriptor 'name' of 'Gui.Workbench' object needs an argument");
		return nullptr;
	}

	// test if twin object isn't already deleted
	if (!static_cast<PyObjectBase*>(self)->isValid()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
		return nullptr;
	}

	try { 
		return Py::new_reference_to(static_cast<WorkbenchPy*>(self)->getMenuText());
	}
	catch (const Py::Exception&)
	{
		// The exception text is already set
		return nullptr;
	}
}
Py::String WorkbenchPy::getMenuText()
{
	return Py::String(getWorkbenchPtr()->MenuText);
}
void WorkbenchPy::staticCallback_setMenuText(PyObject* self, PyObject* value, PyObject* args)
{
	if (!self) {
		PyErr_SetString(PyExc_TypeError, "descriptor 'name' of 'Gui.Workbench' object needs an argument");
		return;
	}

	// test if twin object isn't already deleted
	if (!static_cast<PyObjectBase*>(self)->isValid()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
		return;
	}
	try {
		static_cast<WorkbenchPy*>(self)->setMenuText(Py::String(value, false));
	}
	catch (const Py::Exception&) {
		// The exception text is already set
		
	}
}
void WorkbenchPy::setMenuText(Py::String value)
{
	getWorkbenchPtr()->MenuText = value.as_std_string("ascii");
}

PyObject* WorkbenchPy::staticCallback_getToolTip(PyObject* self, PyObject* args)
{
	// make sure that not a null pointer is passed
	if (!self) {
		PyErr_SetString(PyExc_TypeError, "descriptor 'name' of 'Gui.Workbench' object needs an argument");
		return nullptr;
	}

	// test if twin object isn't already deleted
	if (!static_cast<PyObjectBase*>(self)->isValid()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
		return nullptr;
	}

	try {
		return Py::new_reference_to(static_cast<WorkbenchPy*>(self)->getTtoolTip());
	}
	catch (const Py::Exception&)
	{
		// The exception text is already set
		return nullptr;
	}
}
Py::String WorkbenchPy::getTtoolTip()
{
	return Py::String(getWorkbenchPtr()->ToolTip);
}
void WorkbenchPy::staticCallback_setToolTip(PyObject* self, PyObject* value, PyObject* args)
{
	if (!self) {
		PyErr_SetString(PyExc_TypeError, "descriptor 'name' of 'Gui.Workbench' object needs an argument");
		return;
	}

	// test if twin object isn't already deleted
	if (!static_cast<PyObjectBase*>(self)->isValid()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
		return;
	}
	PyErr_SetString(PyExc_AttributeError, "Attribute 'Objects' of object 'Document' is read-only");
}


PyObject* WorkbenchPy::staticCallback_getIcon(PyObject* self, PyObject* args)
{
	// make sure that not a null pointer is passed
	if (!self) {
		PyErr_SetString(PyExc_TypeError, "descriptor 'name' of 'Gui.Workbench' object needs an argument");
		return nullptr;
	}

	// test if twin object isn't already deleted
	if (!static_cast<PyObjectBase*>(self)->isValid()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
		return nullptr;
	}

	try {
		return Py::new_reference_to(static_cast<WorkbenchPy*>(self)->getIcon());
	}
	catch (const Py::Exception&)
	{
		// The exception text is already set
		return nullptr;
	}
}
Py::String WorkbenchPy::getIcon()
{
	return Py::String(getWorkbenchPtr()->Icon);
}
void WorkbenchPy::staticCallback_setIcon(PyObject* self, PyObject* value, PyObject* args)
{
	if (!self) {
		PyErr_SetString(PyExc_TypeError, "descriptor 'name' of 'Gui.Workbench' object needs an argument");
		return;
	}

	// test if twin object isn't already deleted
	if (!static_cast<PyObjectBase*>(self)->isValid()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
		return;
	}
	PyErr_SetString(PyExc_AttributeError, "Attribute 'Objects' of object 'Document' is read-only");
}

PyObject* WorkbenchPy::staticCallback_Initialize(PyObject* self, PyObject* args)
{
	// make sure that not a null pointer is passed
	if (!self) {
		PyErr_SetString(PyExc_TypeError, "descriptor 'listToolbars' of 'Gui.Workbench' object needs an argument");
		return nullptr;
	}

	// test if twin object isn't already deleted
	if (!static_cast<PyObjectBase*>(self)->isValid()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
		return nullptr;
	}

	// test if object is set Const
	if (static_cast<PyObjectBase*>(self)->isConst()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is immutable, you can not set any attribute or call a non const method");
		return nullptr;
	}

	try { // catches all exceptions coming up from c++ and generate a python exception
		PyObject* ret = static_cast<WorkbenchPy*>(self)->Initialize(args);
		if (ret != 0)
			static_cast<WorkbenchPy*>(self)->startNotify();
		return ret;
	}
	catch (const Py::Exception&)
	{
		// The exception text is already set
		return nullptr;
	}
}

PyObject* WorkbenchPy::staticCallback_GetClassName(PyObject* self, PyObject* args)
{
	// make sure that not a null pointer is passed
	if (!self) {
		PyErr_SetString(PyExc_TypeError, "descriptor 'listToolbars' of 'Gui.Workbench' object needs an argument");
		return nullptr;
	}

	// test if twin object isn't already deleted
	if (!static_cast<PyObjectBase*>(self)->isValid()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
		return nullptr;
	}

	// test if object is set Const
	if (static_cast<PyObjectBase*>(self)->isConst()) {
		PyErr_SetString(PyExc_ReferenceError, "This object is immutable, you can not set any attribute or call a non const method");
		return nullptr;
	}

	try { // catches all exceptions coming up from c++ and generate a python exception
		PyObject* ret = static_cast<WorkbenchPy*>(self)->GetClassName(args);
		if (ret != 0)
			static_cast<WorkbenchPy*>(self)->startNotify();
		return ret;
	}
	catch (const Py::Exception&)
	{
		// The exception text is already set
		return nullptr;
	}
}


//--------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------
WorkbenchPy::WorkbenchPy(Workbench* pcObject, PyTypeObject* T)
	: PyObjectBase(static_cast<PyObjectBase::PointerType>(pcObject), T)
{
}

PyObject* WorkbenchPy::PyMake(struct _typeobject*, PyObject*, PyObject*)  // Python wrapper
{
	// never create such objects with the constructor
	PyErr_SetString(PyExc_RuntimeError, "You cannot create directly an instance of 'WorkbenchPy'.");

	return nullptr;
}

int WorkbenchPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
	return 0;
}
PyObject* WorkbenchPy::_repr()
{
	return Py_BuildValue("s", representation().c_str());
}

PyObject* WorkbenchPy::_getattr(const char* attr)			// __getattr__ function: note only need to handle new state
{
	try {
		// getter method for special Attributes (e.g. dynamic ones)
		PyObject* r = getCustomAttributes(attr);
		if (r) return r;
	} 
	catch (const Py::Exception&)
	{
		// The exception text is already set
		return nullptr;
	}
	PyMethodDef* ml = Methods;
	for (; ml->ml_name != nullptr; ml++) {
		if (attr[0] == ml->ml_name[0] &&
			strcmp(attr + 1, ml->ml_name + 1) == 0)
			return PyCFunction_New(ml, this);
	}
	PyErr_Clear();
	return PyObjectBase::_getattr(attr);
}

int WorkbenchPy::_setattr(const char* attr, PyObject* value) // __setattr__ function: note only need to handle new state
{
	try {
		// setter for special Attributes (e.g. dynamic ones)
		int r = setCustomAttributes(attr, value);
		// r = 1: handled
		// r = -1: error
		// r = 0: ignore
		if (r == 1)
			return 0;
		else if (r == -1)
			return -1;
		return r;
	}
	catch (const Py::Exception&)
	{
		// The exception text is already set
		return -1;
	}

	return PyObjectBase::_setattr(attr, value);
}

Workbench* WorkbenchPy::getWorkbenchPtr() const
{
	return static_cast<Workbench*>(_pcTwinPointer);
}